package AppleCakeMining;
import java.util.ArrayList;


public class ItemSet implements Comparable {
	private ArrayList<Item> items;
	private int support;
	private ArrayList<Transaction> appearsIn;
	
	public ItemSet(Item i, int totalTransactions) {
		this();
		items.add(i);
		support = i.getSupport();
		appearsIn = i.getAppearances();
	}
	
	public ItemSet() {
		this(true);
	}
	
	public ItemSet(boolean b) {
		items = new ArrayList<Item>();
		if(b) {
			GlobalItemSetList.getInstance().addItemSet(this);
		}
	}

	public void addAppearance(Transaction t) {
		if(!appearsIn.contains(t)) {
			appearsIn.add(t);
		}
	}
	
	@Override
	public String toString() {
		String s = "Frequency: " + (float)(support)/GlobalTransactionList.getInstance().getTotalTransactions();
		for(Item i:items) {
			s += " "+ i;
		}
		return s;
	}
	
	public String simple() {
		String s = "";
		for(Item i:items) {
			s += i + " ";
		}
		return s;
	}
	
	public ArrayList<Item> getItems() {
		return items;
	}

	public boolean partialMatch(ItemSet other, int coincidentSize) {
		for(int i = 0; i < coincidentSize; ++i) {
			if(items.get(i).getId() != other.items.get(i).getId()) {
				return false;
			}
		}
		return true;
	}

	public ItemSet merge(ItemSet toMerge) {
		ItemSet merged = new ItemSet();
		merged.items.addAll(items); //all the items from a set
		merged.items.add(toMerge.items.get(toMerge.items.size()-1)); //plus the last item from the other
		merged.calculateSupport(this, toMerge);
		return merged;
	}

	public void calculateSupport(ItemSet subset1, ItemSet subset2) {
		support = 0;
		appearsIn = new ArrayList<Transaction>();
		
		int i1 = 0;
		int i2 = 0;
		while(i1 < subset1.appearsIn.size() && i2 < subset2.appearsIn.size()) {
			int compareTo = subset1.appearsIn.get(i1).compareTo(subset2.appearsIn.get(i2));
			if(compareTo == 0) {
				support++;
				appearsIn.add(subset1.appearsIn.get(i1));
				i1++;
				i2++;
			}
			else if(compareTo < 0) {
				i1++;
			}
			else {
				i2++;
			}
		}
		
		/*
		for(Transaction t:subset1.appearsIn) {
			if(t.containsAll(items)) {
				support++;
				appearsIn.add(t);
			}
		}*/
	}

	public int getSupport() {
		return support;
	}
	
	public float getFrequency() {
		return (float)support / GlobalTransactionList.getInstance().getTotalTransactions();
	}


	public void generateAssociationRules(float minConf) {
		//"bruteforce" method, also only using the full set
		ArrayList<AssociationRule> rules = new ArrayList<AssociationRule>();
		ArrayList<Item> antecedents = new ArrayList<Item>();
		ArrayList<Item> consequents = new ArrayList<Item>();
		generateRules(rules, antecedents, consequents, 0);
		
		for(AssociationRule ar:rules) {
			ar.computeInterestingness(support);
			if(ar.getInterestingness() > minConf) {
				GlobalAssociationRuleList.getInstance().addRule(ar);
				System.out.println(ar);
			}
		}
	}
	
	private void generateRules(ArrayList<AssociationRule> rules, ArrayList<Item> ant, ArrayList<Item> con, int item) {
		if(item >= items.size()) {
			if(ant.size() == 0 || con.size() == 0) return;
			ItemSet antecedent = GlobalItemSetList.getInstance().getItemSet(ant);
			ItemSet consequent = GlobalItemSetList.getInstance().getItemSet(con);
			AssociationRule ar = new AssociationRule(antecedent, consequent);
			rules.add(ar);
			return;
		}
		ArrayList<Item> newAnt = new ArrayList<Item>(ant);
		ArrayList<Item> newCon = new ArrayList<Item>(con);
		Item i = items.get(item);
		newAnt.add(i);
		generateRules(rules, newAnt, newCon, item+1);
		newAnt.remove(i);
		newCon.add(i);
		generateRules(rules, newAnt, newCon, item+1);		
	}
	
	@Override
	public boolean equals(Object obj) {
		if(!(obj instanceof ItemSet)) return false;
		ItemSet toComp = (ItemSet)obj;
		if(items.size() != toComp.items.size()) return false;
		for(int i = 0; i < items.size(); ++i) {
			if(items.get(i) != toComp.items.get(i)) {
				return false;
			}
		}
		return true;
	}

	public void setItems(ArrayList<Item> ant) {
		items = ant;
	}

	@Override
	public int compareTo(Object o) {
		if(! (o instanceof ItemSet)) return 0;
		return support - ((ItemSet)o).support;
	}

	public void clearExtraInfo() {
		appearsIn = null;
	}
}
